<?php
include_once 'Mac/Logger.php';

/**
 * Custom error handler
 * 
 * @author Alan Moreau - moreau.alan@gmail.com
 *
 */
class Mac_ErrorHandler
{
    /**
     * Handle error
     * 
     * @param int $errno the level of the error raised
     * @param string $errstr error message
     * @param string $errfile file where error has occured
     * @param string $errline file line number where the error has occured 
     */
    public static function handleError ($errno, $errstr, $errfile, $errline)
    {
        // if error has been supressed with an @
        if (error_reporting() === 0){
            return;
        }
        
        // defines the log level
        $message = '';
        $logLevel = '';
        switch($errno){
            case E_RECOVERABLE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
            case E_PARSE:
            case E_CORE_ERROR:
            case E_ERROR:
                $logLevel = Mac_Logger::LEVEL_ERROR;
                break;
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
            case E_CORE_WARNING:
            case E_STRICT:
            case E_WARNING:
                $logLevel = Mac_Logger::LEVEL_WARNING;
                break;
            case E_USER_NOTICE:
            case E_NOTICE:
            default: 
                $logLevel = Mac_Logger::LEVEL_INFO;
                break;
        }
        
        // format error message
        $message = sprintf("<b>%s in %s at line %d </b><br />", $errstr, $errfile, $errline);
        $message .= self::debug_string_backtrace(); 
        $logMessage = strip_tags($message);
        
        // if it's a blocking error
        if ($errno & error_reporting()) {
            Mac_Logger::getLogger()->log($logLevel, $logMessage);
            Mac_Controller_Front::getInstance()->dispatchError($message);
        }
        
        Mac_Logger::getLogger()->log($logLevel, $logMessage);
        return false;
    }
    
    /**
     * Handle exception
     * 
     * @param Exception $exception
     */
    public static function handleException ($exception)
    {
        $message = "<b>Uncaught exception %s with message '%s' thrown in %s on line %s</b> <br />%s <br />";
        $message = sprintf(
            $message,
            get_class($exception),
            $exception->getMessage(),
            $exception->getFile(),
            $exception->getLine(),
            self::debug_string_backtrace($exception)
        );

        Mac_Logger::getLogger()->log(Mac_Logger::LEVEL_ERROR, strip_tags($message));
        Mac_Controller_Front::getInstance()->dispatchError($message);
        return false;
    }
    
    /**
     * Retrieve and format the stack trace for display
     */
    private static function debug_string_backtrace ($exception = null)
    {
        $trace = '';
        $stack = array();
        if($exception !== null){
            $stack = $exception->getTrace();
        } else {
            $stack = debug_backtrace();
            array_shift($stack); //shift first element which is handleError function call
            array_shift($stack); //shift second element which is debug_string_backtrace function call
        }
        
        $size = count($stack);
        for($i=0; $i<$size; $i++){
            $trace .= '#'.$i;
            if(isset($stack[$i]['class'])){
                $trace .= ' '.$stack[$i]['class'].$stack[$i]['type'];
            } else {
                $trace .= ' ';
            }
            $trace .= $stack[$i]['function'];
            if(isset($stack[$i]['args'])){
                $trace .= '(';
                $numArgs = count($stack[$i]['args']);
                for($k=0; $k<$numArgs; $k++){
                    if(is_object($stack[$i]['args'][$k])){
                        $trace .= get_class($stack[$i]['args'][$k]);
                    } else if(is_array($stack[$i]['args'][$k])){
                        $trace .= 'Array(';
                        $sizeArray = count($stack[$i]['args'][$k]);
                        $j = 0;
                        foreach($stack[$i]['args'][$k] as $keyArray => $valueKey){
                            if(is_object($valueKey)){
                                $trace .= '[Object]'.$keyArray;
                            } else if(is_array($valueKey)){
                                $trace .= $keyArray.'=>'.' Array(...)';
                            } else {
                                $trace .= $keyArray.'=>'.$valueKey;
                            }
                            if($j !== ($sizeArray-1)){
                                $trace .= ', ';
                            }
                            $j++;
                        }
                    } else {
                        $trace .= $stack[$i]['args'][$k];
                    }

                    if($k !== ($numArgs-1)){
                        $trace .= ', ';
                    }
                }
                $trace .= ')';
            }
            if(isset($stack[$i]['file'])){
                $trace .= ' called at ['.$stack[$i]['file'].':'.$stack[$i]['line'].']';
            }
            $trace .= '<br />';
        }

        return $trace;
    }
}